package org.molamil.acto.utils {
	import flash.display.MovieClip;

	import org.molamil.acto.utils.SomeInstancePropertiesForStatic;
	import org.molamil.acto.utils.ObjectUtils;	

	import flexunit.framework.TestCase;	
	
	/**
	 * @author Jorge Hernandez
	 */
	public class ObjectUtilsTest extends TestCase {
		
		
		// CONSTRUCTOR
		
		public function ObjectUtilsTest(methodName:String = null) {
			super(methodName);
		}
		
		
		// PUBLIC METHODS
		
		public function testMergeDynamic():void {
			
			var o1:Object = this.o1;
			var o2:Object = this.o2;
			
			ObjectUtils.mergeDynamic(o1, o2);
			
			assertEquals("name equals 'Me'", o1["name"], "Me");
			assertEquals("age equals 29", o1["age"], 29);
			assertTrue("today is a Date", o1["today"] is Date);
			assertEquals("surname equals 'Hernandez'", o1["surname"], "Hernandez");
			assertEquals("isCool equals true", o1["isCool"], true);
			assertTrue("tomorrow is a Date", o1["tomorrow"] is Date);
			assertTrue("nothing is null", o1["nothing"] == null);
			assertTrue("o2.age is undefined", o2["age"] == undefined);
		
		}
		
		public function testMergFromDynamicToDynamic():void {
			
			var o1:Object = this.o1;
			var o2:Object = this.o2;
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("name equals 'Me'", o1["name"], "Me");
			assertEquals("age equals 29", o1["age"], 29);
			assertTrue("today is a Date", o1["today"] is Date);
			assertEquals("surname equals 'Hernandez'", o1["surname"], "Hernandez");
			assertEquals("isCool equals true", o1["isCool"], true);
			assertTrue("tomorrow is a Date", o1["tomorrow"] is Date);
			assertTrue("nothing is null", o1["nothing"] == null);
			assertTrue("o2.age is undefined", o2["age"] == undefined);
		
		}
		
		public function testMergeSameClass():void {
			
			var o1:SomeProperties = new SomeProperties();
			
			var o2:SomeProperties = new SomeProperties();
			o2.name = "Pernille";
			o2.surname = "Bengtson";
			o2.dateOfBirth = new Date(1979, 6, 27);
			o2.giveMeHey = function():String {
					return "Hey you!";
				};
			o2.framework = "Acto 2";
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("name equals 'Pernille'", o1.name, "Pernille");
			assertEquals("surname equals 'Bengtson'", o1.surname, "Bengtson");
			assertEquals("age equals 29", o1.age, 29);
			assertEquals("dateOfBirth (date) equals 27", o1.dateOfBirth.getDate(), 27);
			assertEquals("isCool equals true", o1.isCool, true);
			assertEquals("nothing equals null", o1.nothing, null);
			assertEquals("giveMeHey equals 'Hey!'", o1.giveMeHey(), "Hey you!");
			assertEquals("giveMeWow equals 'WOW!'", o1.giveMeWow(), "WOW!");
			
			// Getter/setters don't get merged.
			assertEquals("framework equals 'Acto'", o1.framework, "Acto");
			
		}
		
		public function testMergeSubClass():void {
			
			var o1:SomeProperties = new SomeProperties();
			
			var o2:SomeMoreProperties = new SomeMoreProperties();
			o2.name = "Pernille";
			o2.surname = "Bengtson";
			o2.dateOfBirth = new Date(1979, 6, 27);
			o2.giveMeHey = function():String {
					return "Hey you!";
				};
			o2.framework = "Acto 2";
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("name equals 'Pernille'", o1.name, "Pernille");
			assertEquals("surname equals 'Bengtson'", o1.surname, "Bengtson");
			assertEquals("age equals 29", o1.age, 29);
			assertEquals("dateOfBirth (date) equals 27", o1.dateOfBirth.getDate(), 27);
			assertEquals("isCool equals true", o1.isCool, true);
			assertEquals("nothing equals null", o1.nothing, null);
			assertEquals("giveMeHey equals 'Hey!'", o1.giveMeHey(), "Hey you!");
			assertEquals("giveMeWow equals 'WOW!'", o1.giveMeWow(), "WOW!");
			assertEquals("framework equals 'Acto'", o1.framework, "Acto");
			
		}
		
		public function testMergeFromTypedToTyped():void {
			
			var o1:SomeProperties = new SomeProperties();
			var o2:SomeSimilarProperties = new SomeSimilarProperties();
			
			SomeSimilarProperties.kind = "Pseudo-person";
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("kind equals 'Pseudo-person'", SomeProperties.kind, "Pseudo-person");
			
			assertEquals("name equals 'Ramiro'", o1.name, "Ramiro");
			assertEquals("surname equals 'Hernandez'", o1.surname, "Hernandez");
			assertEquals("age equals 28", o1.age, 28);
			assertEquals("dateOfBirth (date) equals 20", o1.dateOfBirth.getDate(), 20);
			assertEquals("isCool equals false", o1.isCool, false);
			assertEquals("nothing equals null", o1.nothing, null);
			assertEquals("giveMeHey equals 'Hey Ramiro!'", o1.giveMeHey(), "Hey Ramiro!");
			assertEquals("giveMeWow equals 'WOW!'", o1.giveMeWow(), "WOW!");
			
			// Getter/setters don't get merged.
			assertEquals("framework equals 'Acto'", o1.framework, "Acto");
			
		}
		
		public function testMergeFromTypedToDynamic():void {
			
			var o1:Object = this.o1;
			var o2:SomeProperties = new SomeProperties();
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("kind equals 'Person'", o1.kind, SomeProperties.kind);
			
			assertEquals("name equals 'Jorge'", o1.name, o2.name);
			assertEquals("surname equals 'Hernandez'", o1.surname, o2.surname);
			assertEquals("age equals 29", o1.age, 29);
			assertEquals("dateOfBirth equals...", o1.dateOfBirth, o2.dateOfBirth);
			assertEquals("isCool equals true", o1.isCool, o2.isCool);
			assertEquals("nothing equals null", o1.nothing, o2.nothing);
			assertEquals("giveMeHey equals 'Hey!'", o1.giveMeHey(), o2.giveMeHey());
			
			assertTrue("today is a Date", o1["today"] is Date);
			
		}
		
		public function testMergeFromDynamicToTyped():void {
			
			var o1:SomeProperties = new SomeProperties();
			var o2:Object = this.o2;
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("name equals 'Me'", o1.name, o2.name);
			assertEquals("surname equals 'Hernandez'", o1.surname, o2.surname);
			assertEquals("age equals 29", o1.age, 29);
			assertEquals("dateOfBirth (date) equals 21", o1.dateOfBirth.getDate(), 21);
			assertEquals("isCool equals true", o1.isCool, o2.isCool);
			assertEquals("nothing equals null", o1.nothing, o2.nothing);
			assertEquals("giveMeHey equals 'Hey!'", o1.giveMeHey(), "Hey!");
			
			try {
				o1["tomorrow"] == undefined;
				fail("o1.tomorrow should fail");
			} catch (e:ReferenceError) {}
			
		}
		
		public function testDynamicFromMemberToStatic():void {
			
			var o1:SomeSimilarProperties = new SomeSimilarProperties();
			var o2:Object = {kind: "Dynamic person", subkind: "Spanish"};
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("kind equals 'Dynamic person'", SomeSimilarProperties.kind, o2.kind);
			assertEquals("subkind equals 'Spanish'", SomeSimilarProperties.subkind, o2.subkind);
			
		}
		
		public function testMergeFromMemberToStatic():void {
			
			var o1:SomeSimilarProperties = new SomeSimilarProperties();
			var o2:SomeInstancePropertiesForStatic = new SomeInstancePropertiesForStatic();
			
			ObjectUtils.merge(o1, o2);
			
			assertEquals("kind equals 'Instance person'", SomeSimilarProperties.kind, o2.kind);
			assertEquals("subkind equals 'Instance Spanish'", SomeSimilarProperties.subkind, o2.subkind);
			
		}
		
		public function testMergeFromMemberToStaticNoConvert():void {
			
			var o1:SomeSimilarProperties = new SomeSimilarProperties();
			var o2:SomeInstancePropertiesForStatic = new SomeInstancePropertiesForStatic();
			
			SomeSimilarProperties.kind = "Pseudo-person";
			SomeSimilarProperties.subkind = "Brazilian";
			
			ObjectUtils.merge(o1, o2, false);
			
			assertEquals("kind equals 'Pseudo-person'", SomeSimilarProperties.kind, "Pseudo-person");
			assertEquals("subkind equals 'Brazilian'", SomeSimilarProperties.subkind, "Brazilian");
			
		}
		
		public function testGetNestedProperty():void {
			
			var someProperties:SomeProperties = new SomeProperties();
			
			var o1:Object = this.o1;
			o1.anObject = new Object();
			o1.anObject.anotherObject = new Object();
			o1.anObject.anotherObject.someProperties = someProperties;
			
			assertEquals("someProperties.name", someProperties.name, ObjectUtils.getNestedProperty(someProperties, "name"));
			assertEquals("someProperties.giveMeHey", someProperties.giveMeHey, 
						 ObjectUtils.getNestedProperty(someProperties, "giveMeHey"));
			
			assertEquals("o1.name", "Jorge", ObjectUtils.getNestedProperty(o1, "name"));
			assertEquals("o1.name", o1.name, ObjectUtils.getNestedProperty(o1, "name"));
			assertEquals("o1.today", o1.today, ObjectUtils.getNestedProperty(o1, "today"));
			assertEquals("o1.anObject", o1.anObject, ObjectUtils.getNestedProperty(o1, "anObject"));
			assertEquals("o1.anObject.anotherObject", o1.anObject.anotherObject, 
						 ObjectUtils.getNestedProperty(o1, "anObject.anotherObject"));
			assertEquals("o1.anObject.anotherObject.someProperties", o1.anObject.anotherObject.someProperties, 
						 ObjectUtils.getNestedProperty(o1, "anObject.anotherObject.someProperties"));
			
		}
		
		public function testTypedSubProperty():void {
			
			var subProperties:SubProperties = new SubProperties();
			subProperties.someProperties = new SomeProperties();
			
			var o:Object = new Object();
			o["someProperties"] = o2;
			
			assertEquals("subProperties.someProperties before merging", "Jorge", subProperties.someProperties.name);
			
			ObjectUtils.merge(subProperties, o);
			
			assertEquals("subProperties.someProperties.name after merging", "Me", subProperties.someProperties.name);
			
		}
		
		public function testCreateTypedSubProperty():void {
			
			var subProperties:SubProperties = new SubProperties();
			
			var o:Object = new Object();
			o["someProperties"] = o2;
			
			assertNull("subProperties.someProperties before merging", subProperties.someProperties);
			
			ObjectUtils.merge(subProperties, o);
			
			assertEquals("subProperties.someProperties.name after merging", "Me", subProperties.someProperties.name);
			
		}
		
		public function testContainsMethod():void {
			
			var mc:MovieClip = new MovieClip();
			
			assertTrue("mc contains method toString", ObjectUtils.containsMethod(mc, "toString"));
			assertTrue("mc contains method addEventListener", ObjectUtils.containsMethod(mc, "addEventListener"));
			assertTrue("mc contains method prevScene", ObjectUtils.containsMethod(mc, "prevScene"));
			assertFalse("mc does not contain method pizza", ObjectUtils.containsMethod(mc, "pizza"));
			
		}
		
		public function testContainsEmptyMethod():void {
			
			var mc:MovieClip = new MovieClip();
			
			assertTrue("mc contains method toString", ObjectUtils.containsEmptyMethod(mc, "toString"));
			assertFalse("mc does not contain method addEventListener", ObjectUtils.containsEmptyMethod(mc, "addEventListener"));
			assertTrue("mc contains method prevScene", ObjectUtils.containsEmptyMethod(mc, "prevScene"));
			assertFalse("mc does not contain method pizza", ObjectUtils.containsEmptyMethod(mc, "pizza"));
			
		}

		
		// GETTER/SETTER
		
		private function get o1():Object {
			var o1:Object = new Object();
			o1["name"] = "Jorge";
			o1["age"] = 29;
			o1["today"] = new Date(2008, 9, 28);
			return o1;
		}

		private function get o2():Object {
			var o2:Object = new Object();
			o2["surname"] = "Hernandez";
			o2["isCool"] = true;
			o2["tomorrow"] = new Date(2008, 9, 29);
			o2["name"] = "Me";
			o2["nothing"] = null;
			return o2;
		}
		

	}
	
}
